package com.bjsxt;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**TCP 一对多聊天服务器
 * 例如多个人访问同一个网站  聊天群*/
/*有一个公共的数据缓冲区  当客户发送消息时，数据发送到公共缓冲区，接
 * 收消息的线程才启动，从公共缓冲区获取消息，再返回各个客户端*/
/*接收客户端发送消息的线程类*/
class ChatReceive extends Thread{
    private Socket socket ;
    public ChatReceive(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        this.receive();
    }
    private void receive(){
        BufferedReader br =null;
        try {
            br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            while (true){
                String msg = br.readLine();
                //将消息写到公共区，因为接收消息与发送消息互斥 所以用synchronized 对象锁是字符串
                synchronized ("abc"){
                    ChartRoomServer.buf="["+this.socket.getInetAddress()+"]"+msg;
                    "abc".notifyAll();//唤醒对象锁是abc 的全部线程
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(this.socket != null){
                try {
                    this.socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
/*向客户端发送消息的线程类*/
class ChatSend extends Thread{
    private Socket socket;
    public ChatSend(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        this.sendMsg();
    }
    //定义公共数据区的消息发送给客户
    private void sendMsg(){
        //定义字符输出流
        PrintWriter pw = null;
        //Scanner scanner = null; 这里不用键盘输入，因为是从公共数据区获取数据

        try {
            //创建发送消息的流对象
            pw = new PrintWriter(this.socket.getOutputStream());

            //要保证能一直发送消息
            while (true){

                //发送消息时，接收消息线程要处于阻塞状态 所以用synchronized () 互斥
                //锁对象给一个与接收消息线程相同的字符串
                synchronized ("abc") {
                    //让发送消息的线程处于等状态，当接收到公共区有消息时才解除等待
                    "abc".wait();
                    //获取公共数据区的数据
                    pw.println(ChartRoomServer.buf);
                    pw.flush();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(pw != null){
                pw.close();
            }
            if(this.socket != null){
                this.socket=socket;
            }
        }
    }
}
public class ChartRoomServer {
    //定义公共数据区  公共数据区是唯一的，在成员变量加static 是字符串类型
    public static String buf;
    public static void main(String[] args) {
        //主线程作用：建立与客户端持续连接
        System.out.println("Chat Server Version 1.0");
        System.out.println("Listen at 8888.....");
        ServerSocket serverSocket =null;
        try{
            serverSocket = new ServerSocket(8888);
            //让多个客户端连接到同一个端口
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("连接到" + socket.getInetAddress());
                new ChatReceive(socket).start();
                new ChatSend(socket).start();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(serverSocket !=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
